package com.zdp.filesync.nacos.service.impl;

import com.alibaba.nacos.api.config.ConfigType;
import com.zdp.filesync.config.client.FileSyncClient;
import com.zdp.filesync.config.client.FileSyncClientConfig;
import com.zdp.filesync.config.client.FileSyncClientInfo;
import com.zdp.filesync.config.server.FileSyncServer;
import com.zdp.filesync.config.server.FileSyncServerConfig;
import com.zdp.filesync.monitor.config.FileMonitorConfig;
import com.zdp.filesync.monitor.config.FileMonitorInfo;
import com.zdp.filesync.nacos.vo.NamespaceVO;
import com.zdp.filesync.nacos.service.NacosApi;
import com.zdp.filesync.nacos.service.NacosService;
import com.zdp.filesync.nacos.vo.NamespaceDesc;
import com.zdp.filesync.utils.MathUtils;
import com.zdp.filesync.utils.YamlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class NacosServiceImpl implements NacosService {

    private NacosApi nacosApi;

    private FileSyncServer fileSyncServer;

    @Autowired
    private FileMonitorConfig fileMonitorConfig;

    public NacosServiceImpl(NacosApi nacosApi,FileSyncServer fileSyncServer){
        this.nacosApi = nacosApi;
        this.fileSyncServer = fileSyncServer;
    }

    @Override
    public void refreshServerConfig(FileSyncClientConfig syncConfig) {
        // 拉取配置
        if(Objects.isNull(syncConfig)){
            String config = "";
            try{
                config = nacosApi.getConfig(fileSyncServer.getNamespaceId(),fileSyncServer.getDataId(),fileSyncServer.getGroup());
            }catch (Exception e){
                log.error("拉取配置文件:{}失败",fileSyncServer.getDataId(),e);
                throw new RuntimeException(String.format("拉取配置文件:{%s}失败",fileSyncServer.getDataId()));
            }
            syncConfig = YamlUtil.toObject(config, FileSyncClientConfig.class);
        }

        doRefreshServerConfig(syncConfig,fileMonitorConfig);
    }

    private void doRefreshServerConfig(FileSyncClientConfig fileSyncClientConfig,FileMonitorConfig fileMonitorConfig){
        List<FileSyncClientInfo> clientInfos = Optional.ofNullable(fileSyncClientConfig).map(FileSyncClientConfig::getFileSyncClient)
                .map(FileSyncClient::getInfoList).orElseGet(() -> new ArrayList<>());
        // 提取 客户端第一次初始化的配置info
        Map<String,List<FileSyncClientInfo>> infoMap = new HashMap<>();
        clientInfos.stream().filter(info -> 0 == info.getClientVersion() && 0 == info.getServerVersion())
                .forEach(info -> {
                    List<FileSyncClientInfo> infos = infoMap.getOrDefault(info.getMonitorPath(),new ArrayList<>());
                    infos.add(info);
                    infoMap.put(info.getMonitorPath(),infos);
                });
        // 遍历 服务端 监控配置文件内容 / 设置 commentName 以及 serverVersion (用于通知客户端更新)
        List<FileMonitorInfo> fileMonitorInfos = Optional.ofNullable(fileMonitorConfig).map(FileMonitorConfig::getFileMonitorInfos).orElseGet(() -> new ArrayList<>());
        fileMonitorInfos.forEach(monitorInfo -> {
            String monitorPath = monitorInfo.getPath();
            List<FileSyncClientInfo> fileSyncClientInfos = infoMap.get(monitorPath);
            if(!CollectionUtils.isEmpty(fileSyncClientInfos)) {
                fileSyncClientInfos.forEach(info -> {
                    info.setServerVersion(info.getServerVersion() + 1);
                    info.setCommentName(monitorInfo.getCommentName());
                });
            }
        });

        // 推送配置
        String newConfig = YamlUtil.toYaml(fileSyncClientConfig);
        nacosApi.pushConfig(fileSyncServer.getNamespaceId(), fileSyncServer.getDataId(),fileSyncServer.getGroup(),
                newConfig, ConfigType.YAML.getType());
    }

    @Override
    public void initServerConfig(String tenant) {
        // 判断配置文件是否存在
        try{
            String config = nacosApi.getConfig(tenant, fileSyncServer.getDataId(), fileSyncServer.getGroup());
        }catch (Exception e){
            // 说明配置文件不存在
            // 创建配置文件
            nacosApi.pushConfig(tenant,fileSyncServer.getDataId(),fileSyncServer.getGroup(),"file-sync-client.test: 123",null);
        }

    }

    @Override
    public boolean createNacosNamespace() {
        return nacosApi.createNamespace(fileSyncServer.getNamespaceId() ,fileSyncServer.getNamespaceName(),"文件同步服务端配置文件");
    }

    /**
     * 服务端启动，判断是否要进行Nacos命名空间的创建
     */
    @Override
    public void initServer(){
        NamespaceVO namespaceVO = nacosApi.searchNamespace();
        List<NamespaceDesc> namespaceList = namespaceVO.getData();
        if(CollectionUtils.isEmpty(namespaceList)){
            createNacosNamespace();
            initServerConfig(fileSyncServer.getNamespaceId());
        }else{
            // 判断是否存在
            NamespaceDesc namespaceDesc = namespaceList.stream().filter(namespace ->
                            StringUtils.equals(namespace.getNamespaceShowName(), fileSyncServer.getNamespaceName()))
                    .findFirst().orElseGet(()->null);
            if(Objects.isNull(namespaceDesc) ){
                if(createNacosNamespace()){
                    initServerConfig(fileSyncServer.getNamespaceId());
                }else{
                    throw new RuntimeException("初始化命名空间失败");
                }
            }else{
                // 存在的话，创建配置文件
                initServerConfig(namespaceDesc.getNamespace());
            }
        }
    }
}
